#include <Core/BoxApi/ApiManager.h>
#include <Core/BoxApi/AsioBoxConnectionImpl.h>

#include <boost/bind.hpp>

namespace Core { namespace BoxApi {

/**
 * Public ApiManager's api 
 */

ApiManager::ApiManager(ApiManagerParams const & params) : 
	m_recvQueue(),
	m_params(params),
	m_pool(params.conccurency),
	m_lock()
{ 
}

ApiManager::~ApiManager() throw ()
{ 
	interrupt();
}

IBoxConnectionPtr ApiManager::connect(BoxConnectionParams & params) throw (std::exception) 
{
	IBoxConnectionPtr connection(new AsioBoxConnectionImpl(params));
	connection->establishConnection();
	return connection;
}

void ApiManager::postMessage(IBoxConnectionPtr connection, ICommandPtr command) throw (std::exception) 
{
	m_pool.schedule(boost::bind(&ApiManager::sendMessageWrapp, this, connection, command));
}

boost::tuple<ICommandPtr, IBoxConnectionPtr> ApiManager::getNextMessage() throw (std::exception) 
{
	MessageQueueBucket bucket;
	if (m_recvQueue.pop(bucket))
		return boost::make_tuple(bucket.com, bucket.conn);
	return boost::make_tuple(ICommandPtr(), IBoxConnectionPtr());
}

std::list<std::pair<ICommandPtr, IBoxConnectionPtr> > 
	ApiManager::getNextMessages(std::size_t maxMessages) throw (std::exception) 
{
	std::list<std::pair<ICommandPtr, IBoxConnectionPtr> > messages;
	
	if (maxMessages == 0 || maxMessages > m_recvQueue.size())
		maxMessages = m_recvQueue.size();
	
	while (maxMessages > 0) {
		MessageQueueBucket bucket;
		if (m_recvQueue.pop(bucket))
			messages.push_back(std::make_pair(bucket.com, bucket.conn));
		--maxMessages;
	} // while

	return messages;
}

std::size_t ApiManager::getMessageCount() const throw () 
{
	return m_recvQueue.size();
}

void ApiManager::interrupt() throw (std::exception) 
{
	m_recvQueue.setUnblockState(true);
}

/**
 * Private ApiManager's api
 */
void ApiManager::sendMessageWrapp(IBoxConnectionPtr connenction, ICommandPtr command) 
{
	ICommandPtr reply = connenction->sendMessageSync(command);
	if (m_params.connectionCloneAtDone)
		connenction->close();
	MessageQueueBucket queueBucket = { reply, connenction };
	m_recvQueue.push(queueBucket);
}

} } // namespace Core, BoxApi

